package me.aartikov.alligator;


import me.aartikov.alligator.animations.DialogAnimation;
import me.aartikov.alligator.animations.TransitionAnimation;
import me.aartikov.alligator.animations.providers.DefaultDialogAnimationProvider;
import me.aartikov.alligator.animations.providers.DefaultTransitionAnimationProvider;
import me.aartikov.alligator.animations.providers.DialogAnimationProvider;
import me.aartikov.alligator.animations.providers.TransitionAnimationProvider;
import me.aartikov.alligator.listeners.*;
import me.aartikov.alligator.navigationfactories.NavigationFactory;
import me.aartikov.alligator.navigators.*;
import me.aartikov.alligator.screenswitchers.ScreenSwitcher;
import me.aartikov.alligator.commands.Command;
import me.aartikov.alligator.util.Log;
import ohos.aafwk.ability.Ability;
import ohos.aafwk.ability.fraction.FractionAbility;
import ohos.aafwk.ability.fraction.FractionManager;

/**
 * Used to configure an {@link OhosNavigator}.
 */
public class NavigationContext {

    private Ability mActivity;


    private NavigationFactory mNavigationFactory;


    private AbilityNavigator mActivityNavigator;


    private FragmentNavigator mFragmentNavigator;


    private FragmentNavigator mFlowFragmentNavigator;


    private DialogFragmentNavigator mDialogFragmentNavigator;


    private ScreenSwitcher mScreenSwitcher;


    private ScreenSwitchingListener mScreenSwitchingListener;


    private ScreenResultListener mScreenResultListener;


    private NavigationErrorListener mNavigationErrorListener;

    private NavigationContext(Ability activity,
                              NavigationFactory navigationFactory,
                              AbilityNavigator activityNavigator,
                              FragmentNavigator fragmentNavigator,
                              FragmentNavigator flowFragmentNavigator,
                              DialogFragmentNavigator dialogFragmentNavigator,
                              ScreenSwitcher screenSwitcher,
                              ScreenSwitchingListener screenSwitchingListener,
                              ScreenResultListener screenResultListener,
                              NavigationErrorListener navigationErrorListener) {
        mActivity = activity;
        mNavigationFactory = navigationFactory;
        mActivityNavigator = activityNavigator;
        mFragmentNavigator = fragmentNavigator;
        mFlowFragmentNavigator = flowFragmentNavigator;
        mDialogFragmentNavigator = dialogFragmentNavigator;
        mScreenSwitcher = screenSwitcher;
        mScreenSwitchingListener = screenSwitchingListener;
        mScreenResultListener = screenResultListener;
        mNavigationErrorListener = navigationErrorListener;
    }


    public Ability getActivity() {
        return mActivity;
    }


    public NavigationFactory getNavigationFactory() {
        return mNavigationFactory;
    }


    public AbilityNavigator getActivityNavigator() {
        return mActivityNavigator;
    }


    public FragmentNavigator getFragmentNavigator() {
        return mFragmentNavigator;
    }


    public FragmentNavigator getFlowFragmentNavigator() {
        return mFlowFragmentNavigator;
    }


    public DialogFragmentNavigator getDialogFragmentNavigator() {
        return mDialogFragmentNavigator;
    }


    public ScreenSwitcher getScreenSwitcher() {
        return mScreenSwitcher;
    }


    public ScreenSwitchingListener getScreenSwitchingListener() {
        return mScreenSwitchingListener;
    }


    public ScreenResultListener getScreenResultListener() {
        return mScreenResultListener;
    }


    public NavigationErrorListener getNavigationErrorListener() {
        return mNavigationErrorListener;
    }

    /**
     * Builder for a {@link NavigationContext}.
     */
    public static class Builder {

        private Ability mAbility;

        private NavigationFactory mNavigationFactory;

        private FractionManager mFragmentManager;

        private FractionManager mFlowFragmentManager;
//        private int mFlowFragmentContainerId;

        private ScreenSwitcher mScreenSwitcher;

        private TransitionAnimationProvider mTransitionAnimationProvider;

        private DialogAnimationProvider mDialogAnimationProvider;

        private TransitionListener mTransitionListener;

        private ScreenResultListener mScreenResultListener;

        private DialogShowingListener mDialogShowingListener;

        private ScreenSwitchingListener mScreenSwitchingListener;

        private NavigationErrorListener mNavigationErrorListener;

        /**
         * Creates with the given activity.
         *
         * @param activity          activity that should be current when the navigation context is bound.
         * @param navigationFactory navigation factory that was used to create {@link OhosNavigator}
         */
        public Builder(Ability activity, NavigationFactory navigationFactory) {
            mAbility = activity;
            mNavigationFactory = navigationFactory;
        }

        /**
         * Configure fragment navigation
         *
         * @param fragmentManager that will be used for fragment transactions
         * @return this object
         */

        public Builder fragmentNavigation(FractionManager fragmentManager) {
            mFragmentManager = fragmentManager;
            return this;
        }

        /**
         * Configure flow fragment navigation
         *
         * @param fragmentManager that will be used for flow fragment transactions
         * @return this object
         */

        public Builder flowFragmentNavigation(FractionManager fragmentManager) {
            mFlowFragmentManager = fragmentManager;
            return this;
        }

        /**
         * Sets a screen switcher.
         *
         * @param screenSwitcher screen switcher that will be used to switch screens by {@code switchTo} method of {@link Navigator}
         * @return this object
         */

        public Builder screenSwitcher(ScreenSwitcher screenSwitcher) {
            Log.i("Builder.screenSwitcher([screenSwitcher]):202     screenSwitcher:"+screenSwitcher);
            mScreenSwitcher = screenSwitcher;
            return this;
        }

        /**
         * Sets a provider of {@link TransitionAnimation}s.
         *
         * @param transitionAnimationProvider provider of {@link TransitionAnimation}s. By default a provider that returns {@code TransitionAnimation.DEFAULT} is used.
         * @return this object
         */

        public Builder transitionAnimationProvider(TransitionAnimationProvider transitionAnimationProvider) {
            mTransitionAnimationProvider = transitionAnimationProvider;
            return this;
        }

        /**
         * Sets a provider of {@link DialogAnimation}s.
         *
         * @param dialogAnimationProvider provider of {@link DialogAnimation}s. By default a provider that returns {@code DialogAnimation.DEFAULT} is used.
         * @return this object
         */

        public Builder dialogAnimationProvider(DialogAnimationProvider dialogAnimationProvider) {
            mDialogAnimationProvider = dialogAnimationProvider;
            return this;
        }

        /**
         * Sets a transition listener. This listener is called after a screen transition.
         *
         * @param transitionListener transition listener.
         * @return this object
         */

        public Builder transitionListener(TransitionListener transitionListener) {
            mTransitionListener = transitionListener;
            return this;
        }

        /**
         * Sets a dialog showing listener. This listener is called after a dialog has been shown.
         *
         * @param dialogShowingListener dialog showing listener.
         * @return this object
         */

        public Builder dialogShowingListener(DialogShowingListener dialogShowingListener) {
            mDialogShowingListener = dialogShowingListener;
            return this;
        }

        /**
         * Sets a screen switching listener listener. This listener is called after a screen has been switched using {@link ScreenSwitcher}.
         *
         * @param screenSwitchingListener screen switcher listener.
         * @return this object
         */

        public Builder screenSwitchingListener(ScreenSwitchingListener screenSwitchingListener) {
            mScreenSwitchingListener = screenSwitchingListener;
            return this;
        }

        /**
         * Sets a screen result listener. This listener is called when a screen returned result to a previous screen
         *
         * @param screenResultListener screenResultListener screen result listener.
         * @return this object
         */

        public Builder screenResultListener(ScreenResultListener screenResultListener) {
            mScreenResultListener = screenResultListener;
            return this;
        }

        /**
         * Sets a navigation error listener. This listener is called when an error has occurred during {@link Command} execution.
         *
         * @param navigationErrorListener navigation error listener. By default a listener that wraps errors to {@code RuntimeException} and throws it is used.
         * @return this object
         */

        public Builder navigationErrorListener(NavigationErrorListener navigationErrorListener) {
            mNavigationErrorListener = navigationErrorListener;
            return this;
        }

        /**
         * Builds a navigation context
         *
         * @return created navigation context
         */

        public NavigationContext build() {
            TransitionListener transitionListener = mTransitionListener != null ? mTransitionListener : new DefaultTransitionListener();
            TransitionAnimationProvider transitionAnimationProvider = mTransitionAnimationProvider != null ? mTransitionAnimationProvider : new DefaultTransitionAnimationProvider();
            DialogShowingListener dialogShowingListener = mDialogShowingListener != null ? mDialogShowingListener : new DefaultDialogShowingListener();
            DialogAnimationProvider dialogAnimationProvider = mDialogAnimationProvider != null ? mDialogAnimationProvider : new DefaultDialogAnimationProvider();
            ScreenSwitchingListener screenSwitchingListener = mScreenSwitchingListener != null ? mScreenSwitchingListener : new DefaultScreenSwitchingListener();
            ScreenResultListener screenResultListener = mScreenResultListener != null ? mScreenResultListener : new DefaultScreenResultListener();
            NavigationErrorListener navigationErrorListener = mNavigationErrorListener != null ? mNavigationErrorListener : new DefaultNavigationErrorListener();

            AbilityNavigator activityNavigator = new DefaultAbilityNavigator(mAbility, mNavigationFactory, transitionListener, transitionAnimationProvider);

            FragmentNavigator fragmentNavigator = mFragmentManager != null ?
                    new DefaultFragmentNavigator(false, mFragmentManager, mNavigationFactory, transitionListener, screenResultListener, transitionAnimationProvider) : null;

            FragmentNavigator flowFragmentNavigator = mFlowFragmentManager != null ?
                    new DefaultFragmentNavigator(true, mFlowFragmentManager, mNavigationFactory, transitionListener, screenResultListener, transitionAnimationProvider) : null;

            DialogFragmentNavigator dialogFragmentNavigator;
            if (mAbility instanceof FractionAbility) {
                dialogFragmentNavigator = new DefaultDialogFragmentNavigator(((FractionAbility)mAbility).getFractionManager(), mNavigationFactory,
                        dialogShowingListener, screenResultListener, dialogAnimationProvider);
            } else {
                dialogFragmentNavigator = new DefaultDialogFragmentNavigator(null, mNavigationFactory,
                        dialogShowingListener, screenResultListener, dialogAnimationProvider);
            }

            Log.i("Builder.build([]):324   "+mScreenSwitcher);
            return new NavigationContext(mAbility, mNavigationFactory, activityNavigator, fragmentNavigator, flowFragmentNavigator, dialogFragmentNavigator,
                    mScreenSwitcher, screenSwitchingListener, screenResultListener, navigationErrorListener);
        }
    }
}
